package com.bnq.logc.utils;

import android.text.TextUtils;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ExecutorUtil {
    private ExecutorUtil(){
        mExecutor = new ScheduledThreadPoolExecutor(1);
    }
    private List<Task> mTasks = new CopyOnWriteArrayList<>();
    private volatile static ExecutorUtil instance;
    public static ExecutorUtil getInstance(){
        if(instance == null){
            synchronized (ExecutorUtil.class){
                if(instance == null){
                    instance = new ExecutorUtil();
                }
            }
        }
        return instance;
    }

    private ScheduledThreadPoolExecutor mExecutor;

    public void scheduleWithFixedDelay(Task command,long initialDelay,long period, TimeUnit unit){
        if(command != null){
            ScheduledFuture<?> scheduledFuture = mExecutor.scheduleWithFixedDelay(command, initialDelay, period, unit);
            command.mScheduledFuture = scheduledFuture;
            mTasks.add(command);
        }
    }

    public void scheduleAtFixedRate(Task command,long initialDelay,long period, TimeUnit unit){
        if(command != null){
            ScheduledFuture<?> scheduledFuture = mExecutor.scheduleAtFixedRate(command, initialDelay, period, unit);
            command.mScheduledFuture = scheduledFuture;
            mTasks.add(command);
        }
    }

    public void schedule(Task command,long delay, TimeUnit unit){
        if(command != null){
            ScheduledFuture<?> schedule = mExecutor.schedule(command, delay, unit);
            command.mScheduledFuture = schedule;
            mTasks.add(command);
        }
    }

    public boolean removeTask(Task task){
        if(task != null) {
            boolean f = false;
            if(task.mScheduledFuture != null && !task.mScheduledFuture.isCancelled() && !task.mScheduledFuture.isDone()){
                f = task.mScheduledFuture.cancel(true);
            }
            return mTasks.remove(task) && f;
        }
        return false;
    }

    /**
     * 取消并且移除
     * @param id
     */
    public void cancelTask(String id){
        Iterator<Task> iterator = mTasks.iterator();
        while (iterator.hasNext()){
            Task task = iterator.next();
            if(Objects.equals(id, task.id)){
                if(task.mScheduledFuture != null && !task.mScheduledFuture.isCancelled() && !task.mScheduledFuture.isDone()){
                    task.mScheduledFuture.cancel(true);
                    iterator.remove();
                }else if(task.mScheduledFuture != null && (task.mScheduledFuture.isCancelled() || task.mScheduledFuture.isDone())){
                    iterator.remove();
                }
            }
        }
    }

    public void cancel(Task task){
        if(task != null && task.mScheduledFuture != null && !task.mScheduledFuture.isCancelled() && !task.mScheduledFuture.isDone()){
            task.mScheduledFuture.cancel(true);
        }
    }

    public void cancelAllTask(){
        Iterator<Task> iterator = mTasks.iterator();
        while (iterator.hasNext()){
            Task task = iterator.next();
            if(task.mScheduledFuture != null && !task.mScheduledFuture.isCancelled() && !task.mScheduledFuture.isDone()){
                task.mScheduledFuture.cancel(true);
                iterator.remove();
            }else if(task.mScheduledFuture != null && (task.mScheduledFuture.isCancelled() || task.mScheduledFuture.isDone())){
                iterator.remove();
            }
        }
    }

    public Task getScheduleTask(String id){
        Iterator<Task> iterator = mTasks.iterator();
        while (iterator.hasNext()){
            Task task = iterator.next();
            if(TextUtils.equals(id,task.id)){
                return task;
            }
        }
        return null;
    }

    public static abstract class Task implements Runnable{
        public String id;
        public Object tag;
        public ScheduledFuture mScheduledFuture;

        public Task(){
        }

        public Task(String id){
            this.id = id;
        }

        @Override
        public void run() {
            execute();
            if(mScheduledFuture.isDone() || mScheduledFuture.isCancelled()) {
                ExecutorUtil.getInstance().removeTask(this);
            }
        }

        public void cancel(){
            ExecutorUtil.getInstance().cancel(this);
        }

        public abstract void execute();

        @Override
        public String toString() {
            return "Task{" +
                    "id='" + id + '\'' +
                    ", tag=" + tag +
                    ", mScheduledFuture=" + mScheduledFuture +
                    '}';
        }
    }

}

